import 'dart:async';

import 'package:flutter/material.dart';
import 'package:get/get.dart';

abstract class PersistPage<T extends GetxController> extends GetView<T>
    with UtilView {
  T? _controller;

  PersistPage(String key, T controller) : super(key: Key(key)) {
    _controller = controller;
    controller.onInit();
    controller.onReady();
  }

  @override
  T get controller => _controller!;

  void dispose() {
    _controller?.dispose();
    _controller = null;
  }
}

class UtilView {
  Widget textField(
    String val,
    void Function(String, bool) onSubmitted, {
    String labelText = '',
    bool obscureText = false,
    TextInputType keyboardType = TextInputType.text,
    FocusNode? focusNode,
  }) {
    final ctrl = TextEditingController.fromValue(TextEditingValue(
        text: '$val', //判断keyword是否为空
        selection: TextSelection.fromPosition(TextPosition(
            affinity: TextAffinity.downstream, offset: val.length))));
    return TextField(
      obscureText: obscureText,
      keyboardType: keyboardType,
      focusNode: focusNode,
      maxLines: keyboardType == TextInputType.multiline ? null : 1,
      decoration: InputDecoration(
        labelText: labelText,
        isCollapsed: true,
        contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
        border: OutlineInputBorder(
            gapPadding: 0, borderRadius: BorderRadius.circular(5)),
      ),
      onChanged: (text) {
        ctrl.value.copyWith(
            text: text,
            selection: TextSelection.collapsed(offset: text.length));
        onSubmitted(text, false);
      },
      onEditingComplete: () {
        onSubmitted(ctrl.text, true);
      },
      controller: ctrl,
    );
  }

  Future<List<String>?> selectStringList(
      List<String> source, List<String> select) async {
    final completer = Completer();
    final sel =
        source.map((e) => Rx(select.indexOf(e) != -1)).toList(growable: false);
    Get.bottomSheet(
        ListView.builder(
          itemBuilder: (context, index) {
            if (index < source.length) {
              return padding(OutlinedButton.icon(
                onPressed: () {
                  sel[index].value = !sel[index].value;
                },
                icon: Obx(() => Checkbox(
                      value: sel[index].value,
                      onChanged: (val) {
                        if (val != null) sel[index].value = val;
                      },
                    )),
                label: Text(source[index]),
                style: sheetBarBtnStyle(),
              ));
            }
            return padding(OutlinedButton(
              onPressed: () {
                List<String> selList = [];
                for (int i = 0; i < source.length; i++) {
                  if (sel[i].value) selList.add(source[i]);
                }
                Navigator.of(context).pop();
                completer.complete(selList);
              },
              child: Text("确定"),
              style: sheetBarBtnStyle(),
            ));
          },
          itemCount: source.length + 1,
          shrinkWrap: true,
        ),
        barrierColor: Colors.transparent);
    return await completer.future;
  }

  Future<int> selFromList(BuildContext context, List<String> list) async {
    Completer c = new Completer<void>();
    final v = await Get.bottomSheet(
        ListView.builder(
          itemBuilder: (context, index) {
            return padding(OutlinedButton(
                onPressed: () {
                  Navigator.of(context).pop(index);
                  c.complete(index);
                },
                child: Text(list[index]),
                style: sheetBarBtnStyle()));
          },
          itemCount: list.length,
          shrinkWrap: true,
        ),
        barrierColor: Colors.transparent);
    if (v == null) {
      return -1;
    }
    return await c.future;
  }

  Future<String> getInputText(BuildContext context, String tip) async {
    Completer c = new Completer<void>();
    final v = await Get.bottomSheet(
      Container(
        margin: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
        color: Colors.white,
        child: textField("", (val, over) { 
          if (over) {
            Navigator.of(context).pop(val);
            c.complete(val);
          }
        }, labelText: tip),
      ),
      barrierColor: Colors.transparent);
    if (v == null) {
      return "";
    }
    return await c.future;
  }

  Widget padding(Widget child, {double vertical = 2, double horizontal = 30}) {
    return Padding(
        padding:
            EdgeInsets.symmetric(vertical: vertical, horizontal: horizontal),
        child: child);
  }

  ButtonStyle sheetBarBtnStyle() {
    return ButtonStyle(
        backgroundColor: MaterialStateProperty.resolveWith((states) {
          if (states.contains(MaterialState.pressed)) {
            return Color.fromARGB(255, 230, 255, 255);
          }
          return Color.fromARGB(220, 240, 255, 255);
        }),
        padding: MaterialStateProperty.all(
            EdgeInsets.symmetric(vertical: 20, horizontal: 5)));
  }

  Widget outline(Widget child,
      {String? label,
      Widget? rightTop,
      Color? color,
      EdgeInsetsGeometry? padding,
      EdgeInsetsGeometry? margin}) {
    final list = <Widget>[
      Container(
        child: child,
        padding: padding ?? EdgeInsets.all(10),
        margin: margin ?? EdgeInsets.all(20),
        decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(
              color: color ?? Color.fromARGB(20, 0, 0, 0),
              width: 1,
              style: BorderStyle.solid),
          borderRadius: BorderRadius.circular(5),
        ),
      ),
    ];
    if (label != null) {
      list.add(this.padding(
          Text(
            label,
            style:
                TextStyle(color: Colors.black38, fontWeight: FontWeight.bold),
          ),
          vertical: 0,
          horizontal: 20));
    }
    if (rightTop != null) {
      list.add(Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [this.padding(rightTop, vertical: 0, horizontal: 20)],
      ));
    }
    return Stack(children: list);
  }

  Widget autoCompleteTextFeild(
    BuildContext context,
    String val,
    void Function(String, bool) onSubmitted,
    List<List<String>> Function(String text) getCompleteList, {
    String labelText = '',
    TextInputType keyboardType = TextInputType.text,
    RxNotifier ? removeDropdown,
  }) {
    var matchText = "";
    final rval = Rx(val);
    final link = LayerLink();
    final GlobalKey globalKey = GlobalKey();
    var size = Size(200, 30);
    late OverlayEntry overly;
    var show = false;
    final safeRemoveOverlay = () {
      show = false;
      try {
        overly.remove();
      } catch (e) {}
    };
    removeDropdown?.listen((x) { 
      safeRemoveOverlay();
    });
    overly = OverlayEntry(builder: (ctx) {
      final list = getCompleteList(matchText);
      return Positioned(
          child: CompositedTransformFollower(
        offset: Offset(0, size.height + 10),
        link: link,
        child: outline(
            SizedBox(
                width: size.width,
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: list.length,
                  itemBuilder: (context, index) {
                    return GestureDetector(
                      child: Text(list[index][0]),
                      onTap: () {
                        rval.value = list[index][1];
                        onSubmitted(rval.value, false);
                        safeRemoveOverlay();
                      },
                    );
                  },
                )),
            padding: EdgeInsets.zero,
            margin: EdgeInsets.zero,
            color: Colors.blue),
      ));
    });
    final showMatch = (val) {
      size = globalKey.currentContext?.size ?? Size(200, 30);
      matchText = val;
      safeRemoveOverlay();
      Overlay.of(context)?.insert(overly);
      show = true;
    };
    return Container(
        constraints: BoxConstraints(maxWidth: 200),
        child: CompositedTransformTarget(
          key: globalKey,
          link: link,
          child: Focus(
            autofocus: false,
            child: Obx(() => textField(rval.value, (val, over) {
                  if (!over) {
                    showMatch(val);
                  } else {
                    safeRemoveOverlay();
                  }
                  onSubmitted(val, over);
                }, keyboardType: keyboardType)),
            onFocusChange: (focus) {
              if (!focus) safeRemoveOverlay();
              else        showMatch('');
            },
          ),
        ));
  }
}
